%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: 
%% Progress: 
%%
%% Integer math.
%%
%%%%%%%%%%%%%%%%%%%%%%%

-module(intmath).
-export([square/1, pow/2, modspace/2]).
-export([interval_check_exc_exc/3, interval_check_inc_inc/3,
         interval_check_inc_exc/3, interval_check_exc_inc/3]).

square(X) ->
   X * X.

pow(_Base, Exp) when Exp < 0 ->
  error("Bad argument: Negative exponent");
pow(_Base, 0) -> 1;
pow(Base, Exp) ->
  case (Exp rem 2) == 0 of
     true ->
         Square = square(Base),
         pow(Square, Exp div 2);
     false ->
         Base * pow(Base, Exp - 1)
  end.

%% Converts N into a "modulo space".
%% rem is the remainder operation, and not the modulo we want.
modspace(N, Mod) when N < 0 ->
    Mod + (N rem Mod);
modspace(N, Mod) ->
    N rem Mod.

%% The following function checks if Mid belongs to the
%% interval between Low and High in a modulo space. 
%%
%% The first "inc" or "exc" decides if Low is the 
%% including or the excluding interval limit, 
%% if the condition is (Low < Mid) or (Low =< Mid).
%%
%% The second "inc" or "exc" decides the same for High. 
%%
%% There are three possible cases. 
%%
%% The simplest case:
%% ...Low...Mid...High....
%%
%% High have moved past the limit of the modular space
%% and moved to the beginning:
%% ...High...Low...Mid...
%%
%% Both High and Mid have moved past the limit:
%% ...Mid...Low...High...
%%
interval_check_exc_exc(Low, Mid, High) ->
    ((Low < Mid) and (Mid < High)) or
    ((High < Low) and (Low < Mid)) or
    ((Mid < High) and (High < Low)).

interval_check_inc_exc(Low, Mid, High) ->
    ((Low =< Mid) and (Mid < High)) or
    ((High < Low) and (Low =< Mid)) or
    ((Mid < High) and (High < Low)).

interval_check_exc_inc(Low, Mid, High) ->
    ((Low < Mid) and (Mid =< High)) or
    ((High < Low) and (Low < Mid)) or
    ((Mid =< High) and (High < Low)).

interval_check_inc_inc(Low, Mid, High) ->
    ((Low =< Mid) and (Mid =< High)) or
    ((High < Low) and (Low =< Mid)) or
    ((Mid =< High) and (High < Low)).

